﻿/*----------------------------------------------------------------
// 公司名称：公司名称
//
// 产品名称：Gaf
//
// 创 建 人：netcasewqs
// 创建日期：2022/3/4
// 邮    箱：netcasewqs@qq.com
//
// Copyright (C) 2022 Gaf，保留所有权利。
//
//----------------------------------------------------------------*/

using System.Runtime.InteropServices;

namespace Gaf.Impl;

internal static class Win32
{
    internal const string LibraryName = "kernel32";

    [DllImport(LibraryName, CharSet = CharSet.Auto, BestFitMapping = false, SetLastError = true)]
    private static extern IntPtr LoadLibrary(string path);

    [DllImport(Win32.LibraryName, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool FreeLibrary(IntPtr lib);

    internal static Exception GetLastLibraryError() => new System.ComponentModel.Win32Exception();

    internal static bool IsNullOrInvalid(this IntPtr handle) => handle == IntPtr.Zero;

    internal static UnmanagedLibrary LoadUnmanagedLibrary(string dllPath)
    {
        if (string.IsNullOrWhiteSpace(dllPath))
        {
            throw new ArgumentException("A valid library name is expected.", nameof(dllPath));
        }

        if (File.Exists(dllPath) == false) throw new FileNotFoundException(dllPath);

        var handle = NativeLibrary.Load(dllPath);

        return new UnmanagedLibrary(dllPath, handle);
    }
}

internal static class FileUtils
{
    internal static Dictionary<string, string> GetDllPath(string path, bool managedDll)
    {
        Dictionary<string, string> dict = new();
        LoadDllPath(path, dict, managedDll);
        return dict;
    }

    internal static void LoadDllPath(string path, Dictionary<string, string> dict, bool managedDll)
    {
        if (string.IsNullOrEmpty(path)) return;

        var paths = path.Split(new char[] { ';', ',', '，', '；' }, StringSplitOptions.RemoveEmptyEntries);
        paths = managedDll ? paths
            : Environment.Is64BitProcess
                    ? paths.Where(x => IsX64(x)).ToArray()
                    : paths.Where(x => IsX86(x)).ToArray();

        static bool IsX64(string x)
        {
            return string.Equals(x.Trim(), "x64", StringComparison.OrdinalIgnoreCase) || string.Equals(x.Trim(), "amd64", StringComparison.OrdinalIgnoreCase);
        }

        static bool IsX86(string x)
        {
            return string.Equals(x.Trim(), "x86", StringComparison.OrdinalIgnoreCase) || string.Equals(x.Trim(), "i386", StringComparison.OrdinalIgnoreCase);
        }

        foreach (var item in paths)
        {
            var dir = item.Contains(':') ? item : Path.Combine(AppContext.BaseDirectory, item);
            if (!Directory.Exists(dir))
            {
                dir = Path.Combine(AppContext.BaseDirectory, item);
            }

            if (!Directory.Exists(dir)) continue;

            var files = Directory.GetFiles(dir, "*.dll", SearchOption.TopDirectoryOnly).Union(Directory.GetFiles(dir, "*.exe", SearchOption.TopDirectoryOnly)); //todo:*.so

            foreach (var file in files)
            {
                var dllName = new FileInfo(file).Name.Replace(".dll", "", StringComparison.OrdinalIgnoreCase);//todo:*.so
                if (dict.TryGetValue(dllName, out var dllPath))
                {
                    throw new InvalidProgramException($"'{dllPath}' 文件和 '{file}' 文件名称相同！");
                }
                else
                {
                    dict[dllName] = file;
                }
            }

            if (managedDll) //检查托管dll Libs 文件夹下是否有非托管文件夹（）
            {
                var topDirs = Directory.GetDirectories(dir, "*.*", SearchOption.TopDirectoryOnly);
                if (topDirs == null || topDirs.Length == 0) continue;

                var unmanagedDirs = Environment.Is64BitProcess
                    ? topDirs.Select(x => IsX64(x)).ToArray()
                    : topDirs.Select(x => IsX86(x)).ToArray();

                if (unmanagedDirs.Length > 0)
                    LoadDllPath(string.Join(",", unmanagedDirs), dict, false);
            }
        }
    }
}

//internal class NativeBundleActivator : IBundleActivator, IDisposable
//{
//    private readonly UnmanagedLibrary _handle;
//    private readonly Action StartAction;
//    private readonly Action StopAction;

//    private NativeBundleActivator(UnmanagedLibrary handle, Action start, Action stop)
//    {
//        _handle = handle;
//        StartAction = start;
//        StopAction = stop;
//    }

//    public void Dispose() => _handle?.Dispose();

//    public void Start(IBundleContext context) => StartAction?.Invoke();

//    public void Stop(IBundleContext context) => StopAction?.Invoke();

//    public static NativeBundleActivator Create(UnmanagedLibrary handle, string strStartMethod, string strStopMethod)
//    {
//        Action startMethod, stopMethod;
//        PopulateStartAndStopMethod(handle, strStartMethod, strStopMethod, out startMethod, out stopMethod);

//        return new NativeBundleActivator(handle, startMethod, stopMethod);
//    }

//    private static void PopulateStartAndStopMethod(UnmanagedLibrary handle, string strStartMethod, string strStopMethod, out Action startMethod, out Action stopMethod)
//    {
//        strStartMethod = strStartMethod ?? "Start";
//        strStopMethod = strStopMethod ?? "Stop";

//        startMethod = handle.GetUnmanagedFunction<Action>(strStartMethod);
//        if (startMethod == null) startMethod = handle.GetUnmanagedFunction<Action>("Open");
//        //if (startMethod == null)
//        //    throw new ConfigurationErrorsException($"Start method '{strStartMethod}' not found in native bundle Activator '{handle} ");

//        stopMethod = handle.GetUnmanagedFunction<Action>(strStopMethod);
//        if (stopMethod == null) stopMethod = handle.GetUnmanagedFunction<Action>("Close");
//        //if (stopMethod == null)
//        //    throw new ConfigurationErrorsException($"Close method '{strStartMethod}' not found in native bundle Activator '{handle} ");
//    }

//    public override string ToString() => _handle?.ToString();
//}